﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using HowItWentDown.Enemies;
namespace HowItWentDown
{
    public class Player:Obj
    {
        int xdir = 1, zdir = 1;
        public int health = 100;
        Vector3 velocity2 = Vector3.Zero, acc = Vector3.Zero;
        public Vector3 oldVelocity;
        int oldVelocityUpdateTimer = 0;
        Obj carry;
        Boolean diagonal = false;

        public Player(Game1 Doc, float X, float Y, float Z)
            :base(Doc,X,Y,Z,Global.LoadTexture("Prince-2"))
        {
            stationary = false;
            floating = false;
            collision = true;
            pickable = false;
            climbable = false;
            Global.Player = this;
            lookAtCamera = true;
            scale = 0.4f;
            oldVelocity = new Vector3();
            gravity = 0.1f;
        }

        public override void Update()
        {

            #region velocity
            //acceleration modifies the velocity
            velocity2.Z += acc.Z * Global.Speed;
            velocity2.X += acc.X * Global.Speed;

            //slowdown
            acc.Z = -0.1f;
            acc.X = -0.1f;

            // Health test keys
            if (Controls.GetKey(Keys.M) == ControlState.Held)
            {
                health--;
            }
            if (Controls.GetKey(Keys.K) == ControlState.Held)
            {
                health++;
            }

            //movement keys
            if (Controls.GetKey(Keys.W) == ControlState.Held)
            {
                if (Controls.GetKey(Keys.A) == ControlState.Held)
                {
                    //a^2 + b^2 = c^2
                    //c = sqrt(a^2 + b^2)
                    //assume a = b 
                    //c = sqrt(2a^2)
                    //c = 2a
                    diagonal = true;

                    if (zdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.15f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = 1;
                        }
                    }

                    if (xdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.15f * Global.Speed;
                        if (velocity2.X <= 0)
                        {
                            xdir = 1;
                        }
                    }

                }
                else if (Controls.GetKey(Keys.D) == ControlState.Held)
                {
                    diagonal = true;

                    if (zdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.5f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.15f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = 1;
                        }
                    }

                    if (xdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.5f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.150f * Global.Speed;
                        if (velocity2.X <= 0)
                        {
                            xdir = -1;
                        }
                    }
                }
                else
                {
                    diagonal = false;
                    //z += 1;
                    if (zdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.1f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.3f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = 1;
                        }
                    }
                }
            }
            if (Controls.GetKey(Keys.A) == ControlState.Held)
            {
                //diagonal code already handled in Z direction keys
                if (Controls.GetKey(Keys.W) == ControlState.Held || Controls.GetKey(Keys.S) == ControlState.Held)
                {
                    //do nothing
                    diagonal = true;
                }
                else
                {
                    diagonal = false;
                    if (xdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.1f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.3f;
                        if (velocity2.X <= 0)
                        {
                            xdir = 1;
                        }
                    }
                }
            }
            if (Controls.GetKey(Keys.S) == ControlState.Held)
            {
                //z -= 1;
                if (Controls.GetKey(Keys.A) == ControlState.Held)
                {
                    //a^2 + b^2 = c^2
                    //c = sqrt(a^2 + b^2)
                    //assume a = b 
                    //c = sqrt(2a^2)
                    //c = 2a
                    diagonal = true;

                    if (zdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.150f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = -1;
                        }
                    }

                    if (xdir == 1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.150f * Global.Speed;
                        if (velocity2.X <= 0)
                        {
                            xdir = 1;
                        }
                    }

                }
                else if (Controls.GetKey(Keys.D) == ControlState.Held)
                {
                    diagonal = true;
                    if (zdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.150f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = -1;
                        }
                    }

                    if (xdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.05f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.150f * Global.Speed;
                        if (velocity2.X <= 0)
                        {
                            xdir = -1;
                        }
                    }
                }
                else
                {
                    diagonal = false;
                    //z += 1;
                    if (zdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.Z = 0.1f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.Z = -0.3f * Global.Speed;
                        if (velocity2.Z <= 0)
                        {
                            zdir = -1;
                        }
                    }
                }
            }
            if (Controls.GetKey(Keys.D) == ControlState.Held)
            {
                if (Controls.GetKey(Keys.W) == ControlState.Held || Controls.GetKey(Keys.S) == ControlState.Held)
                {
                    //do nothing for here, as it's already handled
                    diagonal = true;
                }
                else
                {
                    diagonal = false;
                    if (xdir == -1)
                    {
                        //if correct direction, accelerate positively
                        acc.X = 0.1f;
                    }
                    else
                    {
                        //if incorrect, accelerate in the opposite direction for a moment, and change direction to be correct.
                        acc.X = -0.3f;
                        if (velocity2.X <= 0)
                        {
                            xdir = -1;
                        }
                    }
                }
            }

            //ensure that velocity does not exceed 1 or drop below 0
            if (velocity2.Z < 0)
                velocity2.Z = 0;

            if (velocity2.X < 0)
                velocity2.X = 0;

            if (diagonal)
            {
                if (velocity2.X > (.50f) * Math.Sqrt(2))
                    velocity2.X = (.50f * (float)Math.Sqrt(2));

                if (velocity2.Z > .50f * Math.Sqrt(2))
                    velocity2.Z = (.50f * (float)Math.Sqrt(2));
            }
            else
            {
                if (velocity2.X > 1.0f)
                    velocity2.X = 1.0f;

                if (velocity2.Z > 1.0f)
                    velocity2.Z = 1.0f;
            }
            // Jumps when space is pressed, and 
            if (y < 1 && !held && Controls.GetKey(Keys.Space) == ControlState.Pressed)
            {
                velocity.Y += 2;
            }
            //double currentSpeed = Math.Sqrt(velocity2.X * velocity2.X + velocity2.Z * velocity2.Z);
            //Console.WriteLine("Velocity: " + currentSpeed);

            //adjust veloctiy with overall velocity and the direction.
            velocity.X = velocity2.X * xdir; velocity.Z = velocity2.Z * zdir;
            //velocity = new Vector3(-Controls.LeftStick.X, 0, Controls.LeftStick.Y);
            /*Vector2 rv;
            rv = MyMath.Direction(pos, Camera.Pos);
            rot.Y = MathHelper.ToDegrees(rv.X);*/

            // Set up a delayed velocity for the companion to use
            if (oldVelocityUpdateTimer > 45)
                oldVelocityUpdateTimer = 0;
            if (oldVelocityUpdateTimer == 0)
                oldVelocity = velocity;
            oldVelocityUpdateTimer++;

            #endregion
            #region picking up and throwing objects
            if (Controls.GetKey(Keys.F) == ControlState.Pressed)
            {
                float dist = float.MaxValue;
                float dist2 = 0;
                bool carrying = false;
                foreach (Obj o in doc.objList)
                {
                    if (o.pickable && (o!=carry))
                    {
                        dist2 = Vector3.Distance(pos, o.pos);
                        if (dist2 < 20 && dist2 < dist)
                        {
                            dist = dist2;
                            if (carry != null)
                                carry.held = false;
                            carry = o;
                            carry.held = true;
                            carrying = true;
                        }
                    }
                }
                if (carry != null && !carrying)
                {
                    dist = float.MaxValue;
                    dist2 = 0;
                    Enemy enemy = null;
                    foreach (Obj o in doc.objList)
                    {
                        if (o is Enemy)
                        {
                            dist2 = Vector3.Distance(pos, o.pos);
                            if (dist2 < 200 && dist2 < dist)
                            {
                                dist = dist2;
                                enemy = (Enemy)o;
                            }
                        }
                    }
                    if (enemy != null)
                    {
                        carry.held = false;
                        carry.velocity = Extensions.Normalize((enemy.pos - carry.pos), 5);
                        carry = null;
                    }
                }
            }
            if (carry != null)
            {
                carry.pos = pos + new Vector3(0,10,0);
            }
            #endregion
            if (z < 0)
                z = 0;
            if (x < 0)
                x = 0;
            if (z > 1600)
                z = 1600;
            if (x > 1600)
                x = 1600;
            // cap health at 100
            if (health > 100)
                health = 100;
            // health cannot go below 0
            else if (health < 0)
                health = 0;

            //Console.WriteLine(rect.Width * scale);
            Obj obj = Collides<ShadowBall>();
            if (obj != null)
            {
                health -= 10;
                obj.remove();
            }
            foreach (Obj collisionObject in doc.objList)
            {
                /*if (collisionObject.GetType() == typeof(ShadowBall))
                {
                    //collisionObject.collisionBox = new BoundingBox(new Vector3(collisionObject.pos.X, collisionObject.pos.Y, collisionObject.pos.Z - 10), new Vector3(collisionObject.pos.X + (collisionObject.rect.Width * collisionObject.scale), collisionObject.pos.Y + (collisionObject.rect.Height * collisionObject.scale), collisionObject.pos.Z + 10));
                    
                    if (this.collisionBox.Intersects(collisionObject.collisionBox))
                    {
                    health -= 10;
                    collisionObject.remove();
                    break;
                    }
                }*/
                if (collisionObject is Cage && collisionObject.CollidesWith(this))
                {
                    //collisionObject.collisionBox = new BoundingBox(new Vector3(collisionObject.pos.X, collisionObject.pos.Y, collisionObject.pos.Z - 10), new Vector3(collisionObject.pos.X + (collisionObject.rect.Width * collisionObject.scale), collisionObject.pos.Y + (collisionObject.rect.Height * collisionObject.scale), collisionObject.pos.Z + 10));
                    //if (this.collisionBox.Intersects(collisionObject.collisionBox))
                    {
                        this.held = true;
                        collisionObject.velocity = Vector3.Zero;
                    }
                }

                if (collisionObject.GetType() == typeof(Crown))
                {
                    collisionObject.collisionBox = new BoundingBox(new Vector3(collisionObject.pos.X, collisionObject.pos.Y, collisionObject.pos.Z - 10), new Vector3(collisionObject.pos.X + (collisionObject.rect.Width * collisionObject.scale), collisionObject.pos.Y + (collisionObject.rect.Height * collisionObject.scale), collisionObject.pos.Z + 10));
                    
                    if (this.collisionBox.Intersects(collisionObject.collisionBox))
                    {
                        doc.win = true;
                        break;
                    }

                }


            }
            base.Update();
            if (y < 0)
            {
                velocity.Y = 0;
                y = 0;
            }
            this.obstacleCollision();
        }
    }
}
